package com.woniuxy.util;

import com.google.errorprone.annotations.Var;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author ：CuiYC
 * @description：
 * @date ：Created in 2025/3/12 14:05
 * @modified By：
 * 线程安不安全如何定义
 *      代码再没有同步干预的情况下，实际执行结果和预期结果是相同的，就是线程安全，否则不是线程安全。
 * 怎么分析：
 *      1：对共享资源出现了非原子性操作，就是不安全代码！！！
 *          共享资源：线程共享
 *          非原子性操作：++ -- 等计算类操作
 *      2：对共享资源出现了并发读写，就是不安全代码！！！
 * 例：操作库存：取，操作（非原子），放
 * 怎么解决不安全代码的问题？
 *      加锁
 * 锁：
 *     1：悲观锁。有可能不安全，一定加锁
 *          1.1：本地锁（JDK锁）
 *              synchronized
 *                  作用：可以使方法或代码块变成同步的。同步代码块/同步代码：同一时间只能有一个线程进入。
 *              lock（JAVA锁接口，ReentrantLock（重入锁））
 *                  ReentrantLock使用步骤
 *                      1：创建锁对象
 *                      2：加锁
 *                      3：释放锁
 *          1.2：分布式锁（一般要借助第三方工具，比如redis）
 *              zookeeper
 *              应用场景：1：项目集群部署 2：出现了线程不安全代码
 *              实现方式：利用Redis实现分布式锁。通过setnx指令的特点实现的
 *              特点：当使用setnx指令放入一个数据时，setnx指令会先判断该key是否存在。
 *              如果存在，则不允许放入。如果不存在，则允许放入。
 *
 *      2：乐观锁
 */
@Component
public class Count {

    public int count = 10;

    ReentrantLock reentrantLock = new ReentrantLock();

    public void sub(){
        try {
//            reentrantLock.lock(); //加锁，没有获取到锁的线程一直等待
//            boolean b = reentrantLock.tryLock();//尝试获取锁，拿不到立即离开
            boolean b = reentrantLock.tryLock(2, TimeUnit.SECONDS);//尝试获取锁，拿不到立即离开
            if (b) {
                if(count > 0){
                    count--; //1：从堆中读取原来的值，2：值-1，3：重新赋值
                }
                Thread.sleep(2000); //当前线程睡眠
            }else {
                //获取不到锁线程
                System.out.println("获取不到锁");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            //是当前线程的，且加上了锁
            if (reentrantLock.isHeldByCurrentThread() && reentrantLock.isLocked() ) {
                reentrantLock.unlock(); //当前线程只能释放当前线程锁
            }
        }
    }
}
